package com.nnnu.wsnackshop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nnnu.wsnackshop.exception.ObjectException;
import com.nnnu.wsnackshop.mapper.StoreAddressesMapper;
import com.nnnu.wsnackshop.pojo.dto.AddStoreDTO;
import com.nnnu.wsnackshop.pojo.dto.StorePageDTO;
import com.nnnu.wsnackshop.pojo.dto.UpdateStoreDTO;
import com.nnnu.wsnackshop.pojo.entity.StoreAddresses;
import com.nnnu.wsnackshop.pojo.entity.Stores;
import com.nnnu.wsnackshop.mapper.StoresMapper;
import com.nnnu.wsnackshop.pojo.vo.StoreAddressVO;
import com.nnnu.wsnackshop.pojo.vo.StoreVO;
import com.nnnu.wsnackshop.result.PageResult;
import com.nnnu.wsnackshop.service.IStoresService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 门店表 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-05-19
 */
@Service
@RequiredArgsConstructor
public class StoresServiceImpl extends ServiceImpl<StoresMapper, Stores> implements IStoresService {
    private final StoreAddressesMapper addrMapper;

    private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public PageResult<StoreVO> pageStores(@NotNull StorePageDTO dto) {
        // 1. 分页拿门店
        Page<Stores> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        LambdaQueryWrapper<Stores> qw = new LambdaQueryWrapper<Stores>()
                .like(StrUtil.isNotBlank(dto.getName()), Stores::getName, dto.getName())
                .eq(dto.getStatus() != null, Stores::getStatus, dto.getStatus())
                .orderByDesc(Stores::getCreatedAt);
        Page<Stores> r = baseMapper.selectPage(page, qw);

        List<Stores> storesList = r.getRecords();
        List<Integer> storeIds = storesList.stream()
                .map(Stores::getId)
                .collect(Collectors.toList());

        // 2. 一次性批量查询所有相关地址
        List<StoreAddresses> addrList = addrMapper.selectList(new LambdaQueryWrapper<StoreAddresses>()
                .in(CollectionUtil.isNotEmpty(storeIds), StoreAddresses::getStoreId, storeIds));
        // 按 storeId 分组
        Map<Integer, List<StoreAddresses>> addrMap = addrList.stream()
                .collect(Collectors.groupingBy(StoreAddresses::getStoreId));

        // 3. 组装 VO
        List<StoreVO> vos = storesList.stream().map(s -> {
            StoreVO vo = BeanUtil.copyProperties(s, StoreVO.class);
            vo.setCreatedAt(s.getCreatedAt().format(FMT));
            vo.setUpdatedAt(s.getUpdatedAt().format(FMT));

            // 填充地址列表
            List<StoreAddressVO> addressVos = addrMap
                    .getOrDefault(s.getId(), Collections.emptyList())
                    .stream()
                    .map(addr -> {
                        StoreAddressVO avo = BeanUtil.copyProperties(addr, StoreAddressVO.class);
                        avo.setCreatedAt(addr.getCreatedAt().format(FMT));
                        avo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
                        return avo;
                    }).collect(Collectors.toList());
            vo.setAddresses(addressVos);

            return vo;
        }).collect(Collectors.toList());

        return PageResult.<StoreVO>builder()
                .total(r.getTotal())
                .items(vos)
                .build();
    }

    @Override
    public StoreVO getStoreDetail(Long id) {
        Stores s = baseMapper.selectById(id);
        if (s == null)
            throw new ObjectException("门店不存在: " + id);
        StoreVO vo = BeanUtil.copyProperties(s, StoreVO.class);
        List<StoreAddresses> addrList = addrMapper.selectByStoreId(s.getId());
        List<StoreAddressVO> addrVos = addrList.stream().map(addr -> {
            StoreAddressVO avo = BeanUtil.copyProperties(addr, StoreAddressVO.class);
            avo.setCreatedAt(addr.getCreatedAt().format(FMT));
            avo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
            return avo;
        }).collect(Collectors.toList());
        vo.setAddresses(addrVos);
        vo.setCreatedAt(s.getCreatedAt().format(FMT));
        vo.setUpdatedAt(s.getUpdatedAt().format(FMT));
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createStore(AddStoreDTO dto) {
        // 唯一性校验
        if (baseMapper.selectCount(
                new LambdaQueryWrapper<Stores>().eq(Stores::getName, dto.getName())) > 0) {
            throw new ObjectException("门店名已存在");
        }
        if (baseMapper.selectCount(
                new LambdaQueryWrapper<Stores>().eq(Stores::getCode, dto.getCode())) > 0) {
            throw new ObjectException("门店编码已存在");
        }
        Stores s = BeanUtil.toBean(dto, Stores.class);
        s.setStatus(1);
        baseMapper.insert(s);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStore(@NotNull UpdateStoreDTO dto) {
        Stores s = baseMapper.selectById(dto.getId());
        if (s == null)
            throw new ObjectException("门店不存在");
        // 校验名称/编码改动后不重复
        if (!s.getName().equals(dto.getName())
                && baseMapper.selectCount(
                        new LambdaQueryWrapper<Stores>().eq(Stores::getName, dto.getName())) > 0) {
            throw new ObjectException("门店名已存在");
        }
        if (!s.getCode().equals(dto.getCode())
                && baseMapper.selectCount(
                        new LambdaQueryWrapper<Stores>().eq(Stores::getCode, dto.getCode())) > 0) {
            throw new ObjectException("门店编码已存在");
        }
        BeanUtil.copyProperties(dto, s);
        baseMapper.updateById(s);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStores(List<Long> ids) {
        if (ids == null || ids.isEmpty())
            throw new ObjectException("删除列表不能为空");
        // 删除级联：store_addresses 已通过 FK CASCADE
        baseMapper.deleteBatchIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void toggleStoreStatus(Long id, Integer status) {
        Stores s = baseMapper.selectById(id);
        if (s == null)
            throw new ObjectException("门店不存在");
        s.setStatus(status);
        s.setUpdatedAt(LocalDateTime.now());
        baseMapper.updateById(s);
    }

    @Override
    public List<StoreVO> getUserStores() {
        // 只查询状态为启用(1)的门店
        LambdaQueryWrapper<Stores> qw = new LambdaQueryWrapper<Stores>()
                .eq(Stores::getStatus, 1)
                .orderByDesc(Stores::getCreatedAt);
        List<Stores> storesList = baseMapper.selectList(qw);

        // 批量查询所有相关地址
        List<Integer> storeIds = storesList.stream()
                .map(Stores::getId)
                .collect(Collectors.toList());

        // 默认空集合
        final Map<Integer, List<StoreAddresses>> addrMap;

        if (CollectionUtil.isNotEmpty(storeIds)) {
            List<StoreAddresses> addrList = addrMapper.selectList(new LambdaQueryWrapper<StoreAddresses>()
                    .in(StoreAddresses::getStoreId, storeIds));
            // 按 storeId 分组
            addrMap = addrList.stream()
                    .collect(Collectors.groupingBy(StoreAddresses::getStoreId));
        } else {
            addrMap = Collections.emptyMap();
        }

        // 组装VO
        return storesList.stream().map(s -> {
            StoreVO vo = BeanUtil.copyProperties(s, StoreVO.class);
            vo.setCreatedAt(s.getCreatedAt().format(FMT));
            vo.setUpdatedAt(s.getUpdatedAt().format(FMT));

            // 填充地址列表
            List<StoreAddressVO> addressVos = addrMap
                    .getOrDefault(s.getId(), Collections.emptyList())
                    .stream()
                    .map(addr -> {
                        StoreAddressVO avo = BeanUtil.copyProperties(addr, StoreAddressVO.class);
                        avo.setCreatedAt(addr.getCreatedAt().format(FMT));
                        avo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
                        return avo;
                    }).collect(Collectors.toList());
            vo.setAddresses(addressVos);

            return vo;
        }).collect(Collectors.toList());
    }
}
